package xyz.heyaoshare.core.service.auth;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import com.mybatisflex.core.query.QueryChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.heyaoshare.config.satoken.context.UserContextHolder;
import xyz.heyaoshare.core.controller.auth.vo.req.UserLoginReqVO;
import xyz.heyaoshare.core.controller.auth.vo.resp.UserInfoRespVO;
import xyz.heyaoshare.core.controller.auth.vo.resp.UserLoginRespVO;
import xyz.heyaoshare.core.entity.system.User;
import xyz.heyaoshare.utils.HttpUtils;
import xyz.heyaoshare.utils.StrUtils;

import java.util.Map;

import static xyz.heyaoshare.exceptions.code.ErrorInfo.*;
import static xyz.heyaoshare.exceptions.customize.ServerException.exception;

/**
 * 认证中心 Service 实现类
 * @author YueHe
 * @version 0.0.1
 * @since 2025/5/20 下午4:32
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    public static final String USERNAME_MAP = "username";
    public static final String NICKNAME_MAP = "nickname";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserLoginRespVO login(UserLoginReqVO vo) {
        // 根据用户名查询用户信息
        User user = QueryChain.of(User.class).eq(User::getUsername, vo.getUsername()).limit(1).one();
        // 用户不存在
        if (user == null) throw exception(USER_OR_PASSWORD_ERROR);
        // 密码认证
        if (!BCrypt.checkpw(vo.getPassword(), user.getPassword())) {
            log.error("密码认证失败");
            throw exception(USER_OR_PASSWORD_ERROR);
        }
        // 执行登录
        try {
            SaLoginParameter loginParameter = new SaLoginParameter();
            loginParameter.setIsLastingCookie(vo.getRememberMe());
            loginParameter.setExtraData(Map.of(USERNAME_MAP, vo.getUsername(), NICKNAME_MAP, user.getNickname()));
            StpUtil.login(user.getId(), loginParameter);

            // 获取登录后的token信息
            SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
            return new UserLoginRespVO(tokenInfo.getTokenName(), tokenInfo.tokenValue, tokenInfo.getTokenTimeout());
        } catch (Exception e) {
            log.error("登录失败", e);
            throw exception(LOGIN_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void logout() {
        String tokenName = StpUtil.getTokenName();
        HttpServletRequest request = HttpUtils.getRequest();
        String token = request.getHeader(tokenName);
        if (StrUtils.isNotBlank(token)) {
            StpUtil.logoutByTokenValue(tokenName);
        }

        HttpServletResponse response = HttpUtils.getResponse();
        response.setHeader(tokenName, StrUtils.EMPTY);
    }

    @Override
    public UserInfoRespVO getUserinfo() {
        User user = UserContextHolder.get();
        if (StpUtil.isLogin() && user != null) {
            return new UserInfoRespVO(user.getUsername(), user.getNickname(), user.getAvatar(), user.getIsAdmin() != null && user.getIsAdmin() == 1);
        }
        StpUtil.logout();
        throw exception(UNAUTHORIZED);
    }

}